﻿using LuaInterface;
using UnityEngine;
using UnityEngine.EventSystems;

namespace Framework.UGUI
{
	public class UILongPressListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler
	{
		public static UILongPressListener Get(GameObject go)
		{
			return go.OnceAddComponent<UILongPressListener>();
		}

		public static UILongPressListener GetWithPath(GameObject go, string path)
		{
			var targetTransform = go.transform.Find(path);
			if (targetTransform != null)
			{
				return Get(targetTransform.gameObject);
			}
			return null;
		}

		public const float DefaultFirstTime = 0.3f;
		public const float DefaultResponseTime = 0.1f;
		private GeneralCallBackWithParam _longPressCallback;
        private GeneralCallBackWithParam _clickCallback;
        private GeneralCallBackWithParam _HoverCallback;
		private float[] _longPressTimeArr;
		private int _longPressIndex;
        private Vector2 _pressDownPos = Vector2.negativeInfinity;

		public void SetLongPressTime(float[] longPressTimeArr)
		{
			_longPressTimeArr = longPressTimeArr;
		}

        public void AddClickListener(LuaFunction luaClick, LuaTable luaTarget, object param = null)
        {
			GeneralCallBackWithParam.GetOrReuse(ref _clickCallback, luaClick, luaTarget, param);
        }

        public void RemoveClickListener()
        {
			GeneralCallBackWithParam.RecycleInst(ref _clickCallback);
            _clickCallback = null;
        }

		public void AddLongPressListener(LuaFunction luaLongPress, LuaTable luaTarget, object param = null)
		{
			GeneralCallBackWithParam.GetOrReuse(ref _longPressCallback, luaLongPress, luaTarget, param);
		}

		public void RemoveLongPressListener()
		{
			GeneralCallBackWithParam.RecycleInst(ref _longPressCallback);
			_longPressTimeArr = null;
			_longPressIndex = 0;
		}
		
		public void AddHoverListener(LuaFunction luaClick, LuaTable luaTarget, object param = null)
		{
			GeneralCallBackWithParam.GetOrReuse(ref _HoverCallback, luaClick, luaTarget, param);
		}
		
		public void RemoveHoverListener()
		{
			GeneralCallBackWithParam.RecycleInst(ref _HoverCallback);
			_HoverCallback = null;
		}

		public void OnPointerDown(PointerEventData eventData)
		{
            if (_clickCallback != null)
            {
	            _pressDownPos = eventData.position;
			}
			if (_longPressCallback != null)
			{
				_longPressIndex = 0;
				float firstWaitTime = _longPressTimeArr != null && _longPressTimeArr.Length > 0 ? _longPressTimeArr[_longPressIndex] : DefaultFirstTime;
				Invoke("OnTimeEnd", firstWaitTime);
			}
		}

		public void OnPointerUp(PointerEventData eventData)
		{
			if (_clickCallback != null)
			{
				var offsetX = Mathf.Abs(_pressDownPos.x - eventData.position.x);
				var offsetY = Mathf.Abs(_pressDownPos.y - eventData.position.y);
				if (_longPressIndex == 0 && offsetX < 1 && offsetY < 1)
				{
					InvokeClickCallback();
				}
				_pressDownPos = Vector2.negativeInfinity;
			}
			if (_longPressCallback != null)
			{
				CancelInvoke("OnTimeEnd");
				_longPressIndex = 0;
			}
		}
		
		public void OnPointerEnter(PointerEventData eventData)
		{
			if (_HoverCallback != null)
			{
				GeneralCallBackWithParam.Invoke(ref _HoverCallback);
			}
		}

		private void OnTimeEnd()
		{
			if (_longPressCallback != null && gameObject.activeInHierarchy)
			{
				InvokeCallback();
				++_longPressIndex;
				float nextWaitTime = DefaultResponseTime;
				if (_longPressTimeArr != null)
				{
					int len = _longPressTimeArr.Length;
					nextWaitTime = _longPressIndex < len ? _longPressTimeArr[_longPressIndex] : _longPressTimeArr[len - 1];
				}
				Invoke("OnTimeEnd", nextWaitTime);
			}
			else
			{
				CancelInvoke("OnTimeEnd");
			}
		}

		private void InvokeCallback()
		{
			if (!Application.isMobilePlatform || Input.touchCount <= 1)
			{
				if (_longPressCallback != null)
				{
					GeneralCallBackWithParam.Invoke(ref _longPressCallback, _longPressIndex);
				}
			}
		}

        private void InvokeClickCallback()
        {
            if (!Application.isMobilePlatform || Input.touchCount <= 1)
            {
                if (_clickCallback != null)
                {
                    GeneralCallBackWithParam.Invoke(ref _clickCallback);
                }
            }
        }

		void OnDestroy()
		{
			if (_longPressCallback != null)
			{
				GeneralCallBackWithParam.RecycleInst(ref _longPressCallback);
				UIEventDebugger.LogUIEventError("UILongPressListener", gameObject);
			}
            if (_clickCallback != null)
            {
                GeneralCallBackWithParam.RecycleInst(ref _clickCallback);
                UIEventDebugger.LogUIEventError("UILongPressListener.click", gameObject);
            }
		}
	}
}
